package ru.spb.osll.myfit.server.handler;

import org.easymock.EasyMock;
import org.easymock.EasyMockSupport;
import org.junit.Before;
import org.junit.Test;
import ru.spb.osll.myfit.common.Content;
import ru.spb.osll.myfit.common.Include;
import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.PageElementType;
import ru.spb.osll.myfit.common.SetUp;
import ru.spb.osll.myfit.common.Table;
import ru.spb.osll.myfit.common.TearDown;
import ru.spb.osll.myfit.server.parser.Constants;
import ru.spb.osll.myfit.server.parser.PageUtils;
import ru.spb.osll.myfit.util.CollectionUtils;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class ContentHandlerTest extends EasyMockSupport {
	private ContentHandler m_handler;
	private PageLoader loader;
	private ContentCreator creator;
	private final String SET_UP = ".SetUp";
	private final String TEAR_DOWN = ".TearDown";
	private String root = "FitNesseRoot";
	private ParentVariablesCreator variablesCreator;

	@Before
	public void setUp() throws SecurityException, NoSuchMethodException {
		Method readPageFileMethod = PageLoader.class.getMethod("readPageFile", String.class);
		loader = createMockBuilder(PageLoader.class).withConstructor().addMockedMethods(readPageFileMethod).createMock();

//		Method getParentVariablesMap = ParentVariablesCreator.class.getMethod("getParentVariablesMap", String.class);
//		variablesCreator = createMockBuilder(ParentVariablesCreator.class).withConstructor().addMockedMethod(getParentVariablesMap).createMock();

		variablesCreator = createStrictMock(ParentVariablesCreator.class);
		
		creator = createMock(ContentCreator.class);
		m_handler = new ContentHandler(root, loader, creator, variablesCreator);
	}

	@Test
	public void testLoadPageWithInclude() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("!include .TestInclude");
		List<String> SimpleInckudeList = CollectionUtils.list("|set node regeneration submit delay|30 min|");

		String name = "PageWithImport";
		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));

		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));

		String nameInclude = ".TestInclude";
		EasyMock.expect(loader.readPageFile(getFullPath(nameInclude))).andReturn(SimpleInckudeList);

		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		//EasyMock.replay(loader, variablesCreator);
		
		replayAll();
		Page page = m_handler.loadPage(name);

		assertEquals(1, page.countPageElements());
		assertEquals(PageElementType.INCLUDE.getKey(), page.getElement(0).getType().getKey());
		Include include = (Include) page.getElement(0);
		assertEquals(".TestInclude", include.getPath());
		Page pageInclude = include.getPage();
		assertEquals(1, pageInclude.countPageElements());
		assertEquals(PageElementType.TABLE, pageInclude.getElement(0).getType());
		verifyAll();
	}

	@Test
	public void testLoadSimplePage() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|");
		String name = "SimPlePage";

		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));

		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		EasyMock.replay(loader, variablesCreator);

		Page page = m_handler.loadPage(name);
		EasyMock.verify(loader, variablesCreator);

		assertEquals(2, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));
		assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
				PageUtils.tableToString((Table) page.getElement(1)));

	}

	@Test
	public void testLoadPageWithImports() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("|Import|", "|ru.spb.osll.myfit.examples|", Constants.LINE_SEPARATOR,
				"|set node regeneration submit delay|30 min|");

		String name = "PageWithImport";

		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));
		
		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		replayAll();

		Page page = m_handler.loadPage(name);

		assertEquals(1, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));

		EasyMock.verify(loader);
	}

	@Test
	public void testLoadPageWithSetUp() throws IOException {

		List<String> SimpleLoadList = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|", Constants.LINE_SEPARATOR);
		String name = "SimPlePage";

		List<String> SimpleSetUp = CollectionUtils.list("|Import|", "|ru.spb.osll.myfit.examples|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|1000000|files of size|10KB|using|80|threads|", Constants.LINE_SEPARATOR);

		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andReturn(SimpleSetUp);
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));
		
		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		replayAll();
		
		Page page = m_handler.loadPage(name);

		assertEquals(3, page.countPageElements());
		assertEquals(PageElementType.SET_UP, page.getElement(0).getType());

		SetUp setUpinclude = (SetUp) page.getElement(0);
		Page pageSetUp = setUpinclude.getPage();

		assertEquals(1, pageSetUp.countPageElements());
		assertEquals(PageElementType.TABLE, page.getElement(1).getType());
		assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(1)));

		assertEquals(PageElementType.TABLE, page.getElement(2).getType());

		assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
				PageUtils.tableToString((Table) page.getElement(2)));

		EasyMock.verify(loader);
	}

	@Test
	public void testLoadPageWithTearDown() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|", Constants.LINE_SEPARATOR);
		String name = "SimPlePage";

		List<String> SimpleTearnDown = CollectionUtils.list("|Import|", "|ru.spb.osll.myfit.examples|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|1000000|files of size|10KB|using|80|threads|", Constants.LINE_SEPARATOR);

		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andReturn(SimpleTearnDown);

		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		replayAll();
		
		Page page = m_handler.loadPage(name);

		assertEquals(3, page.countPageElements());
		assertEquals(PageElementType.TABLE, page.getElement(0).getType());
		assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));

		assertEquals(PageElementType.TABLE, page.getElement(1).getType());

		assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
				PageUtils.tableToString((Table) page.getElement(1)));
		assertEquals(PageElementType.TEAR_DOWN, page.getElement(2).getType());
		TearDown setUpinclude = (TearDown) page.getElement(2);
		Page pageSetUp = setUpinclude.getPage();
		assertEquals(1, pageSetUp.countPageElements());
		EasyMock.verify(loader);
	}

	@Test
	public void testLoadRecursiveInclude() throws IOException {
		List<String> pageList1 = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|", Constants.LINE_SEPARATOR, "!include .TestPage2");
		List<String> pageList2 = CollectionUtils.list("!include .TestPage1");
		String pageName1 = "TestPage1";

		String pageName2 = ".TestPage2";

		EasyMock.expect(loader.readPageFile(getFullPath(pageName1))).andReturn(pageList1);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(pageName2))).andReturn(pageList2);
	
		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(pageName1, root)).andReturn(map);
		replayAll();

		Page page = m_handler.loadPage(pageName1);
		// System.err.println(page.countPageElements());

		assertEquals(3, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));
		assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
				PageUtils.tableToString((Table) page.getElement(1)));
		assertEquals(PageElementType.INCLUDE_ERROR, page.getElement(2).getType());
		EasyMock.verify(loader);
	}

	@Test
	public void testLoadNotExistingInclude() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|", Constants.LINE_SEPARATOR, "!include .NotExistingInclude");
		String name = "SimPlePage";

		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(".NotExistingInclude"))).andThrow(new FileNotFoundException(""));
		
		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		replayAll();
		
		Page page = m_handler.loadPage(name);
		
		assertEquals(3, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));
		assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
				PageUtils.tableToString((Table) page.getElement(1)));
		assertEquals(PageElementType.INCLUDE_ERROR, page.getElement(2).getType());
		EasyMock.verify(loader);
	}

	@Test
	public void testLoadPageWithContent() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|", "!contents -R2");
		String name = "SimPlePage";

		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));
		Content content = new Content(2);

		EasyMock.expect(creator.createContent(root, name, 2)).andReturn(content);

		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		replayAll();
		
		Page page = m_handler.loadPage(name);
		EasyMock.verify(loader, creator);

		assertEquals(3, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));
		assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
				PageUtils.tableToString((Table) page.getElement(1)));
		assertEquals(content, page.getElement(2));
	}
	
	
	@Test
  public void testLoadPageWithContentsLevelAll() throws IOException {
    List<String> SimpleLoadList = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
        "|write|10|files of size|10KB|using|10|threads|", "!contents -R");
    String name = "SimPlePage";

    EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
    EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
    EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));
    Content content = new Content(Content.CONTENTS_LEVEL_ALL);

    EasyMock.expect(creator.createContent(root, name, Content.CONTENTS_LEVEL_ALL)).andReturn(content);

    HashMap<String, String> map = new HashMap<String, String>();
    EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
    replayAll();
    
    Page page = m_handler.loadPage(name);
    EasyMock.verify(loader, creator);

    assertEquals(3, page.countPageElements());
    assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));
    assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
        PageUtils.tableToString((Table) page.getElement(1)));
    assertEquals(content, page.getElement(2));
  }

	 @Test
	  public void testLoadPageWithContentsLevel1() throws IOException {
	    List<String> SimpleLoadList = CollectionUtils.list("|set node regeneration submit delay|30 min|", Constants.LINE_SEPARATOR, "|with cubetools|",
	        "|write|10|files of size|10KB|using|10|threads|", "!contents");
	    String name = "SimPlePage";

	    EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
	    EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
	    EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));
	    Content content = new Content(1);

	    EasyMock.expect(creator.createContent(root, name, 1)).andReturn(content);

	    HashMap<String, String> map = new HashMap<String, String>();
	    EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
	    replayAll();
	    
	    Page page = m_handler.loadPage(name);
	    EasyMock.verify(loader, creator);

	    assertEquals(3, page.countPageElements());
	    assertEquals("|set node regeneration submit delay|30 min|" + Constants.LINE_SEPARATOR, PageUtils.tableToString((Table) page.getElement(0)));
	    assertEquals("|with cubetools|" + Constants.LINE_SEPARATOR + "|write|10|files of size|10KB|using|10|threads|" + Constants.LINE_SEPARATOR,
	        PageUtils.tableToString((Table) page.getElement(1)));
	    assertEquals(content, page.getElement(2));
	  }
	
	
	@Test
	public void testContentInInclude() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("!include .PageWithContent");
		String name = "SimPlePage";

		List<String> PageWithContentList = CollectionUtils.list("!contents -R3");

		EasyMock.expect(loader.readPageFile(getFullPath(name))).andReturn(SimpleLoadList);
		EasyMock.expect(loader.readPageFile(getFullPath(SET_UP))).andThrow(new FileNotFoundException(""));
		EasyMock.expect(loader.readPageFile(getFullPath(TEAR_DOWN))).andThrow(new FileNotFoundException(""));

		EasyMock.expect(loader.readPageFile(getFullPath(".PageWithContent"))).andReturn(PageWithContentList);

		Content content = new Content(3);
		EasyMock.expect(creator.createContent(root, ".PageWithContent", 3)).andReturn(content);

		HashMap<String, String> map = new HashMap<String, String>();
		EasyMock.expect(variablesCreator.getParentVariablesMap(name, root)).andReturn(map);
		replayAll();
		
		Page page = m_handler.loadPage(name);
		EasyMock.verify(loader, creator);

		assertEquals(1, page.countPageElements());
		Include include = (Include) page.getElement(0);
		assertEquals(1, include.getPage().countPageElements());
		assertEquals(content, include.getPage().getElement(0));
	}

	private String getFullPath(String pagePath) {
		return PageUtils.getFullPathToContent(root, pagePath);
	}
}
